package com.yzq.os.spider.v.service.domain;

import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import com.yzq.os.spider.v.dao.QueryURLDao;
import com.yzq.os.spider.v.domain.QueryURL;

@Service
public class QueryURLService {

	private static final String QUERY_URL_TABLE_NAME_PREFIX = "query_url_";

	private Logger logger = Logger.getLogger(QueryURLService.class);

	@Autowired
	private QueryURLDao queryURLDao;

	public void save(int searchEngineId, QueryURL url) {
		String tableName = makeQueryUrlTableName(searchEngineId);
		List<QueryURL> urls = new ArrayList<QueryURL>();
		urls.add(url);
		queryURLDao.batchSave(tableName, urls);
	}

	public void batchSave(int searchEngineId, List<QueryURL> urls, int eachMaxOpt) {
		String tableName = makeQueryUrlTableName(searchEngineId);
		int totalSize = urls.size();
		int processedSize = 0;
		Iterator<QueryURL> it = urls.iterator();
		List<QueryURL> willSaveList = new ArrayList<QueryURL>();
		while (it.hasNext()) {
			willSaveList.add(it.next());
			if (willSaveList.size() >= eachMaxOpt) {
				batchSave(tableName, willSaveList);
				processedSize += willSaveList.size();
				logger.debug("Saved query url size:[" + CollectionUtils.size(willSaveList) + "] in tableName:[" + tableName + "] totalSize:[" + totalSize + "] percent:[" + percentComplete(totalSize, processedSize) + "]");
				willSaveList.clear();
			}
		}
		if (CollectionUtils.isNotEmpty(willSaveList)) {
			batchSave(tableName, willSaveList);
			processedSize += willSaveList.size();
			logger.debug("Saved query url size:[" + CollectionUtils.size(willSaveList) + "] in tableName:[" + tableName + "] percent:[" + percentComplete(totalSize, processedSize) + "]");
			willSaveList.clear();
		}
	}

	private static String percentComplete(int totalSize, int processedSize) {
		if (totalSize == 0) {
			return null;
		}
		double t = totalSize;
		double p = processedSize;
		double percent = (p / t) * 100;
		DecimalFormat format = new DecimalFormat("#0.00");
		return format.format(percent) + "%";
	}

	private String makeQueryUrlTableName(int searchEngineId) {
		return QUERY_URL_TABLE_NAME_PREFIX + searchEngineId;
	}

	private void batchSave(String tableName, List<QueryURL> urls) {
		queryURLDao.batchSave(tableName, urls);
	}

	public void updateDoFlag(int searchEngineId, QueryURL queryURL) {
		String tableName = makeQueryUrlTableName(searchEngineId);
		List<QueryURL> urls = new ArrayList<QueryURL>();
		urls.add(queryURL);
		queryURLDao.batchUpdateDoFlag(tableName, urls);
	}

	@Transactional(isolation = Isolation.READ_COMMITTED)
	public List<QueryURL> findWillDoWithTryTime(int searchEngineId, int maxReturn) throws JsonParseException, JsonMappingException, IOException {
		return findWillDoFromDatabase(searchEngineId, maxReturn);
	}

	public synchronized List<QueryURL> findWillDoFromDatabase(int searchEngineId, int maxReturn) {
		String tableName = makeQueryUrlTableName(searchEngineId);
		List<QueryURL> urls = queryURLDao.find(tableName, searchEngineId, 0, maxReturn);
		for (QueryURL url : urls) {
			url.setDoFlag(1);// doing
		}
		queryURLDao.batchUpdateDoFlag(tableName, urls);
		return urls;
	}

	public void truncate(int searchEngineId) {
		String tableName = makeQueryUrlTableName(searchEngineId);
		queryURLDao.truncate(tableName);
		logger.info("Truncate query url table searchEngineId:[" + searchEngineId + "]");
	}

	public List<String[]> procStatistics(int searchEngineId) {
		String tableName = makeQueryUrlTableName(searchEngineId);
		return queryURLDao.procStatistics(searchEngineId, tableName);
	}

	public List<String[]> progressbar(int searchEngineId) {
		String tableName = makeQueryUrlTableName(searchEngineId);
		List<String[]> list = queryURLDao.procStatistics(searchEngineId, tableName);
		Map<String, int[]> map = new HashMap<String, int[]>();
		for (String[] row : list) {
			int[] in;
			if (!map.containsKey(row[1])) {
				in = new int[2];
			} else {
				in = map.get(row[1]);
			}
			putProgressbarData(row, in);
			map.put(row[1], in);
		}
		List<String[]> result = new ArrayList<String[]>();
		for (String key : map.keySet()) {
			int[] in = map.get(key);
			double processed = in[1];
			double total = in[0];
			double d = 100;
			double rate = Math.rint(processed / (total / d));
			int rate_i = Double.valueOf(rate).intValue();
			result.add(new String[] { key, String.valueOf(in[0]), String.valueOf(in[1]), String.valueOf(rate_i) });
		}
		return result;
	}

	private void putProgressbarData(String[] row, int[] in) {
		in[0] += Integer.parseInt(row[3]);// total
		if (!StringUtils.equals(row[2], "0") && !StringUtils.equals(row[2], "1")) {
			// not will do and not doing
			in[1] += Integer.parseInt(row[3]);
		}
	}

	public void initValidBakQueryUrls(int searchEngineId) {
		String tableName = makeQueryUrlTableName(searchEngineId);
		queryURLDao.initValidBakQueryUrls(searchEngineId, tableName);
		logger.info("Insert into query url table with bak query urls. eId:[" + searchEngineId + "] tableName:[" + tableName + "].");
	}

	public void createTable(int searchEngineId) {
		String tableName = makeQueryUrlTableName(searchEngineId);
		queryURLDao.createTable(tableName);
	}

	public int count(int searchEngineId) {
		String tableName = makeQueryUrlTableName(searchEngineId);
		return queryURLDao.countOnlineTable(tableName);
	}

	public void batchSaveToBackTable(int searchEngineId, String[] urls) {
		queryURLDao.batchSaveToBackTable(searchEngineId, urls);
	}

	public void batchSaveToBackTable(int searchEngineId) {
		queryURLDao.batchSaveToBackTable(makeQueryUrlTableName(searchEngineId));
	}

	public void deleteValidBakQueryUrls(int searchEngineId) {
		queryURLDao.deleteValidBakQueryUrls(searchEngineId);
	}

	public List<String> findFirstValidBakQueryUrl(int searchEngineId, int maxReturn) {
		return queryURLDao.findFirstValidBakQueryUrl(searchEngineId, maxReturn);
	}
}
